﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace HardStyle.SimpleRSAUtil
{
    /// <summary>
    ///  Dotnet environment uses key in XML format
    /// </summary>
    public class RSAUtil
    {
        public static string Encrypt(string publicKeyXml, string plaintext, int dwKeySize = 2048)
        {
            return Encrypt(publicKeyXml, Encoding.UTF8.GetBytes(plaintext), dwKeySize);
        }

        public static string Encrypt(string publicKeyXml, byte[] valueBytes, int dwKeySize = 2048)
        {
            using RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(dwKeySize);
            rsa.FromXmlString(publicKeyXml);
            var buffer = new byte[dwKeySize / 8 - 11];
            using var valueSteam = new MemoryStream(valueBytes);
            using var memSteam = new MemoryStream();
            var readCount = 0;
            while ((readCount = valueSteam.Read(buffer, 0, buffer.Length)) > 0)
            {
                var readBytes = new byte[readCount];
                Array.Copy(buffer, 0, readBytes, 0, readCount);
                memSteam.Write(rsa.Encrypt(readBytes, false));
                memSteam.Flush();
            }
            rsa.Clear();
            return Convert.ToBase64String(memSteam.ToArray());
        }

        public static string Decrypt(string privateKeyXml, string ciphertext, int dwKeySize = 2048)
        {
            return Decrypt(privateKeyXml, Convert.FromBase64String(ciphertext), dwKeySize);
        }

        public static string Decrypt(string privateKeyXml, byte[] valueBytes, int dwKeySize = 2048)
        {
            using RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(dwKeySize);
            rsa.FromXmlString(privateKeyXml);
            var buffer = new byte[dwKeySize / 8];
            var readCount = 0;
            using var valueSteam = new MemoryStream(valueBytes);
            using var memSteam = new MemoryStream();
            while ((readCount = valueSteam.Read(buffer, 0, buffer.Length)) > 0)
            {
                var readBytes = new byte[readCount];
                Array.Copy(buffer, 0, readBytes, 0, readCount);
                memSteam.Write(rsa.Decrypt(readBytes, false));
                memSteam.Flush();
            }
            rsa.Clear();
            return Encoding.UTF8.GetString(memSteam.ToArray());
        }

        public static string CreateSignature(string privateKeyXml, string encrypt)
        {
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
            {
                rsa.FromXmlString(privateKeyXml);
                byte[] dataBytes = Encoding.UTF8.GetBytes(encrypt);
                byte[] signatureBytes = rsa.SignData(dataBytes, "SHA256");
                return Convert.ToBase64String(signatureBytes);
            }
        }

        public static bool ValidateSignature(string publicKeyXml, string encrypt, string signature)
        {
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
            {
                rsa.FromXmlString(publicKeyXml);
                RSAPKCS1SignatureDeformatter rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
                //指定解密的时候HASH算法为SHA256
                rsaDeformatter.SetHashAlgorithm("SHA256");

                byte[] deformatterData = Convert.FromBase64String(signature);
                using (HashAlgorithm sha256 = HashAlgorithm.Create("SHA256"))
                {
                    byte[] hashData = sha256.ComputeHash(Encoding.UTF8.GetBytes(encrypt));
                    return rsaDeformatter.VerifySignature(hashData, deformatterData);
                }
            }
        }
    }
}
